package com.xbongbong.paas.service;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.FieldAttrConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.AddressEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.RelTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ClueUserEntity;
import com.xbongbong.saas.domain.entity.CustomerUserEntity;
import com.xbongbong.saas.domain.entity.PublicGroupSeniorEntity;
import com.xbongbong.saas.domain.entity.RuleSeniorEntity;
import com.xbongbong.saas.domain.entity.TransferBackRuleSeniorEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.CustomerSeniorRuleTypeEnum;
import com.xbongbong.saas.enums.SeniorFixedGroupEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.subform.ClueTeamEnum;
import com.xbongbong.saas.enums.subform.CustomerTeamEnum;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author yanglei
 * @ProjectName xbb-pro
 * @Description: 公海高级模式抽象类
 * @date 2022/4/13 10:59
 */
@Service
public abstract class AbstractPublicSeniorRuleService {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractPublicSeniorRuleService.class);

    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;

    /**
     * 公海高级模式 - 获取规则需要退回公海的客户列表
     * @param userEntity 用户
     * @param rule 规则
     * @param idIn 用户的客户id列表（不一定是所有的客户）
     * @param advanceTime 提醒时间
     * @param explainMap 当前表单开启的字段
     * @param labelIds 当前表单开启的标签id
     * @param openGroupIdList 当前表单开启的分组id
     * @param deleteGroupIdList 当前删除的分组id
     * @param noGroupId 当前表单无分组id
     * @param allGroupList 当前表单的全部分组
     * @return
     * @throws XbbException
     * 创建时间： 2022-4-18 上午9:41:37
     * 修改时间： 2018-4-18 上午9:41:37
     * @author yanglei
     */
    public abstract List<RuleSeniorEntity> getSeniorBackCustomerList(UserEntity userEntity, TransferBackRuleSeniorEntity rule, List<Long> idIn, Integer advanceTime, Long menuId,Map<String, Integer> explainMap,List<Long> labelIds,List<Long> openGroupIdList, List<Long> deleteGroupIdList,Long noGroupId,List<PublicGroupSeniorEntity> allGroupList) throws XbbException ;

    /**
     * 公海高级模式 - 获取规则需要退回公海的线索列表
     * @param userEntity 用户
     * @param rule 规则
     * @param idIn 用户的线索id列表
     * @param advanceTime 提醒时间
     * @param explainMap 当前表单开启的字段
     * @param labelIds 当前表单开启的标签id
     * @param openGroupIdList 当前表单开启的分组id
     * @param deleteGroupIdList 当前删除的分组id
     * @param noGroupId 当前表单无分组id
     * @param allGroupList 当前表单的全部分组
     * @return
     * @throws XbbException
     * 创建时间： 2022-5-9 上午9:41:37
     * 修改时间： 2018-5-9 上午9:41:37
     * @author yanglei
     */
    public abstract List<RuleSeniorEntity> getSeniorBackClueList(UserEntity userEntity, TransferBackRuleSeniorEntity rule, List<Long> idIn, Integer advanceTime,Map<String, Integer> explainMap,List<Long> labelIds,List<Long> openGroupIdList, List<Long> deleteGroupIdList,Long noGroupId,List<PublicGroupSeniorEntity> allGroupList) throws XbbException ;

    /***
     * 公海高级模式退回规则 - 获取特殊员工和所有员工最小的天数
     * @param triggerRuleArray
     * @param user
     * @return
     */
    public Map<String,Integer> getBackMinDayMap(JSONArray triggerRuleArray ,UserEntity user){
        //特殊员工map
        Map<String, Integer> specialMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //所有员工
        Map<String, Integer> allUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        //获当前员工的所属部门和角色
        List<Long> deptIds;
        try {
            deptIds = JSONArray.parseArray(user.getDepartment(), Long.class);
        } catch (Exception e) {
            deptIds = new ArrayList<>();
        }
        if (deptIds == null) {
            deptIds = new ArrayList<>();
        }
        List<Integer> roleIds = new ArrayList<>();
        String role = user.getRoleIds();
        if (StringUtil.isNotEmpty(role)) {
            roleIds = StringUtil.roleIdToListInt(role);
        }
        if (roleIds == null) {
            roleIds = new ArrayList<>();
        }
        //获取退回规则触发条件的特殊员工，如果
        for (Object obj : triggerRuleArray){
            JSONObject triggerRuleJson = (JSONObject) obj;

            JSONArray depts = FastJsonHelper.getJsonArrayOrDefault(triggerRuleJson, "depts", new JSONArray());
            JSONArray roles = FastJsonHelper.getJsonArrayOrDefault(triggerRuleJson, "roles", new JSONArray());
            JSONArray users = FastJsonHelper.getJsonArrayOrDefault(triggerRuleJson, "users", new JSONArray());
            List<String> userIdList = new ArrayList<>();
            List<Long> deptIdList = new ArrayList<>();
            List<Integer> roleIdList = new ArrayList<>();
            if (Objects.nonNull(users)) {
                userIdList = JSON.parseArray(users.toJSONString(), String.class);
            }
            if (Objects.nonNull(depts)) {
                deptIdList = JSON.parseArray(depts.toJSONString(), Long.class);
            }
            if (Objects.nonNull(roles)) {
                roleIdList = JSON.parseArray(roles.toJSONString(), Integer.class);
            }
            //当前员工所属部门是否在特殊员工配置
            deptIdList.retainAll(deptIds);
            //当前员工所属角色是否在特殊员工配置
            roleIdList.retainAll(roleIds);
            //证明该配置是特殊员工配置
            Boolean specialConfig = CollectionsUtil.isNotEmpty(users) || CollectionsUtil.isNotEmpty(depts) || CollectionsUtil.isNotEmpty(roles);
            //当前员工不在特殊员工里面
            Boolean configFail = !userIdList.contains(user.getUserId()) && deptIdList.isEmpty() && roleIdList.isEmpty();
            if(specialConfig && configFail){
                //改配置是特殊员工配置，但是当前员工不在特殊员工里面，所以改配置对当前员工无效，直接跳过
                continue ;
            }
            Integer backTime = FastJsonHelper.getIntegerOrDefault(triggerRuleJson, "value", 0);
            //如果配置设置的天数为0 ，改配置无效
            if (Objects.equals(backTime,BasicConstant.ZERO)){
                continue;
            }
            calculateMinDayMap(user.getUserId(),specialConfig,backTime,specialMap,allUserMap);
        }

        Iterator<Map.Entry<String, Integer>> it = allUserMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Integer> entry = it.next();
            String key = entry.getKey();

            Integer integer = specialMap.get(key);
            if (Objects.nonNull(integer)) {
                // 如果特殊员工和全部员工 退回类型重复，则以特殊员工为主
                it.remove();
            }
        }
        specialMap.putAll(allUserMap);
        return specialMap;
    }

    /**
     * 获取最终的特殊员工和所有员工对应的最小天数的map
     * @param userId 当前用户id
     * @param backtime 配置天数
     * @param specialConfig 是否特殊员工配置
     * @param specialMinDayMap  特殊员工map
     * @param allMinDayMap  所有员工map
     */
    public void calculateMinDayMap(String userId ,Boolean specialConfig ,Integer backtime, Map<String, Integer> specialMinDayMap, Map<String, Integer> allMinDayMap){
        //所有员工,相同员工取最小值
        Integer allUserValue = allMinDayMap.get(userId);
        if(!specialConfig){
            if (Objects.isNull(allUserValue)) {
                allMinDayMap.put(userId,backtime);
            } else {
                if(allUserValue < backtime){
                    allMinDayMap.put(userId, allUserValue);
                }
            }
            return;
        }
        //特殊员工,相同员工取最小值
        Integer specialValue = specialMinDayMap.get(userId);
        if (Objects.isNull(specialValue)){
            specialMinDayMap.put(userId, backtime);
            return;
        }
        if(specialValue < backtime){
            specialMinDayMap.put(userId, specialValue);
        }
    }


    /**
     * @Description: 判断客户分配时间是否超过规则设置的天数
     * @param distributionTime 分配时间
     * @param ruleDay 规则设置的天数
     * @return
     * 创建时间： 2022-4-21 下午2:06:53
     * 修改时间： 2022-4-21下午2:06:53 chy
     * @author copy chy
     * @since v3.22
     * @version v3.22
     */
    public boolean distributionTimeExceedRuleTime(Long distributionTime, Integer ruleDay){

        Long second = ruleDay * 86400L;
        if(distributionTime!=null){
            //捞取客户的时间在规则时间之内
            if((DateTimeUtil.getInt() - distributionTime) < second){
                return false;
            }
        }else{
            //当分配时间是空的时候也不用处理
            return false;
        }
        return true;
    }


    /***
     * 公海高级模式转移规则 - 获取设置最小的天数
     * @param triggerRuleArray 触发条件
     * @return 最小天数
     */
    public Integer getTransferMinDayMap(JSONArray triggerRuleArray){
        List<Integer> list = new ArrayList<>();
        for (Object obj : triggerRuleArray){
            JSONObject triggerRuleJson = (JSONObject) obj;
            Integer transferTime = FastJsonHelper.getIntegerOrDefault(triggerRuleJson, "value", 0);
            if (Objects.equals(transferTime,BasicConstant.ZERO)){
                continue;
            }
            list.add(transferTime);
        }
        return Collections.min(list);
    }


    /**
     * 设置客户退回或者退回公海池的公海池提醒内容
     * @param customer 客户实体
     * @param ruleName 规则名称
     * @param newTime 最新的客户联系时间、合同签订时间、机会添加时间(也可能是分配时间)
     * @param day 规则中限制的天数（不算上提前量）
     * @param ruleType 规则类型
     */
    public void setLeftDay(RuleSeniorEntity customer, String ruleName, Long newTime, Integer day,Integer ruleType,String userName){
        Long leftDay = 0L;

        Long now = DateTimeUtil.getInt();
        //应该退回的时间
        Long backTime = newTime + (day * 86400L);
        //现在到退回时间的时间间隔
        Long leftTime = backTime - now;
        if(leftTime > 0) {
            //正常提醒
            leftDay = leftTime / TimeConstant.SECONDS_PER_DAY;
            if(leftTime % TimeConstant.SECONDS_PER_DAY > 0) {
                leftDay ++;
            }
        }
        String tagMemo = "";
        String name = "";
        if (Objects.equals(ruleType, CustomerSeniorRuleTypeEnum.BACK_RULE.getCode())){
            tagMemo = StringConstant.PUBLIC_TAG_MEMO;
            name = userName;
        }else if(Objects.equals(ruleType, CustomerSeniorRuleTypeEnum.TRANSFER_RULE.getCode())){
            tagMemo = StringConstant.TRANSFER_TAG_MEMO;
            name = customer.getName();
        }

        leftDay = leftDay < 1 ? 1 : leftDay;

        String memo = String.format(I18nMessageUtil.getMessage(tagMemo), name, ruleName, leftDay);

        customer.setNotifyMemo(memo);
        customer.setRuleName(ruleName);
        customer.setLeftDay(leftDay);
    }


    /**
     * 获取目标公海id,如果客户所绑定公海分组未启用，或者已删除，该客户不退回公海池
     * @param retList 需要退回或转移的客户
     * @param ruleValue 退回规则
     * @param groupList 当前模板的所有分组列表
     * @param businessType 业务类型
     * @param objectGroupId 目标公海分组id
     */
    public void analysisObjectGroup(List<RuleSeniorEntity> retList,JSONObject ruleValue,List<PublicGroupSeniorEntity> groupList,Integer businessType,Long objectGroupId){
        Map<Long, Long> idParentIdMap = groupList.stream().collect(Collectors.toMap(PublicGroupSeniorEntity::getId, PublicGroupSeniorEntity::getParentId));
        Map<Long, String> idNameMap = groupList.stream().collect(Collectors.toMap(PublicGroupSeniorEntity::getId, PublicGroupSeniorEntity::getName));
        Map<Long, Integer> idGroupTypeMap = groupList.stream().collect(Collectors.toMap(PublicGroupSeniorEntity::getId, PublicGroupSeniorEntity::getGroupType));

        SeniorFixedGroupEnum seniorFixedGroupEnum = SeniorFixedGroupEnum.NO_GROUP_CUSTOMER;
        if(Objects.equals(businessType,XbbRefTypeEnum.CLUE.getCode())){
            seniorFixedGroupEnum = SeniorFixedGroupEnum.NO_GROUP_CLUE;
        }
        //目标公海当前分组和上级分组时的处理
        for (RuleSeniorEntity ruleSenior : retList){
            String publicGroupIdStr = ruleSenior.getPublicGroupId();
            formatObjectGroupIdAndName(ruleSenior,objectGroupId,publicGroupIdStr,idParentIdMap,idNameMap,idGroupTypeMap,seniorFixedGroupEnum);
        }
    }


    public void formatObjectGroupIdAndName(RuleSeniorEntity item,Long objectGroupId,String publicGroupIdStr
            ,Map<Long, Long> idParentIdMap, Map<Long, String> idNameMap,Map<Long, Integer> idGroupTypeMap,SeniorFixedGroupEnum fixedGroupEnum){
        //最终所需要保存的当前分组和目标分组
        String finalObjectGroupId = "";
        String finalObjectGroupName = "";
        String finalPublicGroupName = "";
        //判断目标公海分组属于上级、当前、无分组、还是普通分组
        if (Objects.equals(objectGroupId, SeniorFixedGroupEnum.CURRENT_GROUP.getId())){
            //目标公海分组为当前分组处理
            //为空代表改客户所绑定的分组是无公海分组
            if (StringUtil.isEmpty(publicGroupIdStr)){
                finalPublicGroupName = fixedGroupEnum.getLabel();
                finalObjectGroupId = "";
                finalObjectGroupName = fixedGroupEnum.getLabel();
            }else {
                finalObjectGroupId = item.getPublicGroupId();
                finalObjectGroupName = idNameMap.getOrDefault(Long.valueOf(finalObjectGroupId),"");
                finalPublicGroupName = idNameMap.getOrDefault(Long.valueOf(publicGroupIdStr),"");
            }
        }else if(Objects.equals(objectGroupId, SeniorFixedGroupEnum.PREVIOUS_GROUP.getId())){
            //目标公海分组为上级分组处理
            if (StringUtil.isEmpty(publicGroupIdStr)){
                finalPublicGroupName = fixedGroupEnum.getLabel();
                finalObjectGroupId = "";
                finalObjectGroupName = fixedGroupEnum.getLabel();
            }else {
                Long parentId = idParentIdMap.getOrDefault(Long.valueOf(publicGroupIdStr), 0L);
                //如果是最顶级分组，上级分组就是当前分组
                finalObjectGroupId = Objects.equals(parentId,0L) ? publicGroupIdStr : String.valueOf(parentId);
                finalObjectGroupName = idNameMap.getOrDefault(Long.valueOf(finalObjectGroupId),"");
                finalPublicGroupName = idNameMap.getOrDefault(Long.valueOf(publicGroupIdStr),"");
            }
        }else if(Objects.equals(idGroupTypeMap.get(objectGroupId),BasicConstant.TWO)){
            //目标公海分组为无公海分组处理
            if (StringUtil.isEmpty(publicGroupIdStr)){
                finalPublicGroupName = fixedGroupEnum.getLabel();
            }else {
                finalPublicGroupName = idNameMap.getOrDefault(Long.valueOf(publicGroupIdStr),"");
            }
            finalObjectGroupId = "";
            finalObjectGroupName = SeniorFixedGroupEnum.NO_GROUP_CUSTOMER.getLabel();
        }else {
            if (StringUtil.isEmpty(publicGroupIdStr)){
                finalPublicGroupName = fixedGroupEnum.getLabel();
            }else {
                finalPublicGroupName = idNameMap.getOrDefault(Long.valueOf(publicGroupIdStr),"");
            }
            finalObjectGroupId = String.valueOf(objectGroupId);
            finalObjectGroupName =  idNameMap.getOrDefault(Long.valueOf(finalObjectGroupId),"");
        }
        item.setObjectGroupId(finalObjectGroupId);
        item.setObjectGroupName(finalObjectGroupName);
        item.setPublicGroupName(finalPublicGroupName);
    }


    /**
     * 解析适用范围，封装成筛选条件
     * @param applyScopeArray 适用范围
     * @param businessType 业务类型
     * @param openGroupIdList 当前模板开启的分组id列表
     * @param deleteGroupIdList 当前模板删除的分组id列表
     * @param noGroupId 当前模板开启的无分组线索、客户分组的id
     */
    public List<List<ConditionsEntityExt>> packageApplyScoreCondition(JSONArray applyScopeArray,Integer businessType,List<Long> openGroupIdList,List<Long> deleteGroupIdList,Long noGroupId){
        List<List<ConditionsEntityExt>> applyScoreShouldCondition = new ArrayList<>();
        String attr = CustomerManagementEnum.PUBLIC_GROUP.getAttr();
        if (Objects.equals(businessType,XbbRefTypeEnum.CLUE.getCode())){
            attr = ClueEnum.PUBLIC_GROUP.getAttr();
        }
        if (CollectionsUtil.isNotEmpty(applyScopeArray)){
            List<Long> applyScopeIds = new ArrayList<>();
            for (Object applyScopeObj : applyScopeArray){
                JSONObject applyScope = (JSONObject) applyScopeObj;
                applyScopeIds.add(applyScope.getLong("value"));
            }
            //全部分组处理 0 全部客户，-1 全部线索
            if (applyScopeIds.contains(BasicConstant.ZERO_LONG) || applyScopeIds.contains(BasicConstant.ONE_LONG_MINUS)){
                applyScopeIds = new ArrayList<>(openGroupIdList);
            }
            //普通分组取交集
            applyScopeIds.retainAll(openGroupIdList);
            //无分组处理
            List<ConditionsEntityExt> noGroupConditionList = new ArrayList<>();
            List<ConditionsEntityExt> deleteGroupConditionList = new ArrayList<>();
            if (applyScopeIds.contains(noGroupId)){
                //1、封装没绑定分组的缇欧埃安
                ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt();
                conditionsEntityExt.setAttr(attr);
                conditionsEntityExt.setFieldType(FieldTypeEnum.PUBLIC_GROUP.getType());
                conditionsEntityExt.setSymbol(ConditionEnum.EMPTY.getSymbol());
                noGroupConditionList.add(conditionsEntityExt);
                //2、若客户或者线索绑定分组已经删除，也算无公海分组，所以这里也要封装已经删除的分组id
                ConditionsEntityExt deleteGroupCondition = new ConditionsEntityExt();
                deleteGroupCondition.setAttr(attr);
                deleteGroupCondition.setFieldType(FieldTypeEnum.PUBLIC_GROUP.getType());
                deleteGroupCondition.setSymbol(ConditionEnum.IN.getSymbol());
                deleteGroupCondition.setValue(new ArrayList<>(deleteGroupIdList));
                deleteGroupConditionList.add(deleteGroupCondition);
                applyScoreShouldCondition.add(noGroupConditionList);
                applyScoreShouldCondition.add(deleteGroupConditionList);
            }
            if (CollectionsUtil.isEmpty(applyScopeIds)) {
                //用于占位
                applyScopeIds = Arrays.asList(0L);
            }
            //普通分组处理，直接封装分组条件
            List<ConditionsEntityExt> groupConditionList = new ArrayList<>();
            ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt();
            conditionsEntityExt.setAttr(attr);
            conditionsEntityExt.setFieldType(FieldTypeEnum.PUBLIC_GROUP.getType());
            conditionsEntityExt.setSymbol(ConditionEnum.IN.getSymbol());
            conditionsEntityExt.setValue(new ArrayList<>(applyScopeIds));
            groupConditionList.add(conditionsEntityExt);
            applyScoreShouldCondition.add(groupConditionList);
        }
        return applyScoreShouldCondition;
    }


    /**
     * 根据筛选条件过滤需要退回或者转移的客户
     * @param dataIdIn 客户id
     * @param conditionList 筛选条件
     * @param applyScoreShouldCondition 适用范围筛选条件
     * @param corpid	公司id
     * @param formId	模板id
     * @param relAlias 1、and，2、or
     * @param isPublic 查询是否公海的客户
     * @param menuId 表示只查客户，不查经销商
     * @return List<RuleSeniorEntity>
     * @throws XbbException
     */
    public List<RuleSeniorEntity> getCustomerListByEs(List<Long> dataIdIn,List<ConditionsEntityExt> conditionList,List<List<ConditionsEntityExt>> applyScoreShouldCondition, String corpid,Long formId,String relAlias, Integer isPublic,Long menuId) throws XbbException {
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_STATEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        Integer businessType = XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode();
        //排序：id asc
        List<SortBuilder> sortBuilderList = Arrays.asList(new FieldSortBuilder(new FieldSortBuilder(BasicConstant.ID).order(SortOrder.ASC)));
        //限制返回值
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,customerIndex.getType()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,BasicConstant.ZERO));
        boolQueryBuilder.filter(termQuery("formId",formId));
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.PASS.getType(), FlowStatusEnum.NOT_NEED_APPROVAL.getType())));
        boolQueryBuilder.filter(termQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.IS_PUBLIC),isPublic));
//        if (StringUtil.isNotEmpty(userId)){
//            HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(IndexTypeEnum.IDX_SAAS_CUSTOMER_TEAM, corpid, BasicConstant.ONE, Arrays.asList(userId));
//            //查询该用户负责的客户
//            boolQueryBuilder.filter(hasChildQueryBuilder);
//        }
        //只查客户，不查经销商
        if (menuId != null){
            boolQueryBuilder.filter(termQuery("menuId",menuId));
        }
        if (CollectionsUtil.isNotEmpty(dataIdIn)){
            boolQueryBuilder.filter(termsQuery("id",dataIdIn));
        }
        if (Objects.equals(relAlias,RelTypeEnum.OR.getAlias())){
            List<List<ConditionsEntityExt>> shouldConditionList = new ArrayList<>();
            for (ConditionsEntityExt conditionsEntityExt : conditionList){
                shouldConditionList.add(Arrays.asList(conditionsEntityExt));
            }
            EsUtil.parseShouldCondition(boolQueryBuilder,shouldConditionList, relAlias,corpid, businessType);
        }else {
            //适用范围
            EsUtil.parseShouldCondition(boolQueryBuilder,applyScoreShouldCondition,relAlias,corpid, businessType);
            EsUtil.parseCondition(boolQueryBuilder,conditionList, relAlias,corpid, businessType);
        }
        //分页
        XbbAggregatedPage<CustomerEntityExt> xbbAggregatedPage = esHelper.findByPage(customerIndex, boolQueryBuilder, CustomerEntityExt.class, null, 0, 1000, sortBuilderList);
        List<CustomerEntityExt> content = xbbAggregatedPage.getContent();
        return transferCustomerRuleList(content,corpid,businessType);
    }

    /**
     * 根据筛选条件过滤需要退回或者转移的线索
     * @param dataIdIn 线索id
     * @param conditionList 筛选条件
     * @param applyScoreShouldCondition 适用范围筛选条件
     * @param corpid	公司id
     * @param formId	模板id
     * @param relAlias 1、and，2、or
     * @param isPublic 查询是否公海的线索
     * @return List<RuleSeniorEntity>
     * @throws XbbException
     */
    public List<RuleSeniorEntity> getClueListByEs(List<Long> dataIdIn,List<ConditionsEntityExt> conditionList,List<List<ConditionsEntityExt>> applyScoreShouldCondition,String corpid,Long formId,String relAlias,Integer isPublic) throws XbbException {
        Integer businessType = XbbRefTypeEnum.CLUE.getCode();
        //排序：id asc
        List<SortBuilder> sortBuilderList = Arrays.asList(new FieldSortBuilder(new FieldSortBuilder(BasicConstant.ID).order(SortOrder.ASC)));
        //限制返回值
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,BasicConstant.ZERO));
        boolQueryBuilder.filter(termQuery("formId",formId));
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.PASS.getType(), FlowStatusEnum.NOT_NEED_APPROVAL.getType())));
        boolQueryBuilder.filter(termQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.IS_PUBLIC),isPublic));
        if (CollectionsUtil.isNotEmpty(dataIdIn)){
            boolQueryBuilder.filter(termsQuery("id",dataIdIn));
        }
//        if (StringUtil.isNotEmpty(userId)){
//            HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(IndexTypeEnum.IDX_SAAS_CLUE_TEAM, corpid, BasicConstant.ONE, Arrays.asList(userId));
//            //查询该用户负责的线索
//            boolQueryBuilder.filter(hasChildQueryBuilder);
//        }
        if (Objects.equals(relAlias,RelTypeEnum.OR.getAlias())){
            List<List<ConditionsEntityExt>> shouldConditionList = new ArrayList<>();
            for (ConditionsEntityExt conditionsEntityExt : conditionList){
                shouldConditionList.add(Arrays.asList(conditionsEntityExt));
            }
            EsUtil.parseShouldCondition(boolQueryBuilder,shouldConditionList, relAlias,corpid, businessType);
        }else {
            //适用范围
            EsUtil.parseShouldCondition(boolQueryBuilder,applyScoreShouldCondition,relAlias,corpid, businessType);
            EsUtil.parseCondition(boolQueryBuilder,conditionList, relAlias,corpid, businessType);
        }
        //分页
        XbbAggregatedPage<ClueEntityExt> xbbAggregatedPage = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_CLUE, boolQueryBuilder, ClueEntityExt.class, null, 0, 1000, sortBuilderList);
        List<ClueEntityExt> content = xbbAggregatedPage.getContent();
        return transferClueRuleList(content,corpid,businessType);
    }



    public List<RuleSeniorEntity> transferCustomerRuleList(List<CustomerEntityExt> customerList,String corpid ,Integer businessType){
        List<PaasFormEntityExt> paasFormEntityList = paasFormModel.getEnableFormList(corpid, businessType);
        Map<Long, String> idToFormName = paasFormEntityList.stream().collect(Collectors.toMap(PaasFormEntityExt::getId, PaasFormEntityExt::getName));
        List<RuleSeniorEntity> ruleSeniorEntityList = new ArrayList<>();
        if (CollectionsUtil.isNotEmpty(customerList)){
            for (CustomerEntityExt customer : customerList){
                RuleSeniorEntity ruleEntity = new RuleSeniorEntity();
                if (customer != null){
                    Long lastOppotunityTime = customer.getSysDate2() != null ? customer.getSysDate2() : 0L;
                    Long lastSignTime = customer.getSysDate1() != null ? customer.getSysDate1() : 0L;
                    JSONObject data = customer.getData();
                    ruleEntity.setId(customer.getId());
                    ruleEntity.setCorpid(customer.getCorpid());
                    ruleEntity.setAppId(customer.getAppId());
                    ruleEntity.setFormId(customer.getFormId());
                    ruleEntity.setFormName(idToFormName.getOrDefault(customer.getFormId(),""));
                    ruleEntity.setMenuId(customer.getMenuId());
                    ruleEntity.setName(data.getString(CustomerManagementEnum.NAME.getAttr()));
                    ruleEntity.setLastConnectTime(data.getLongValue(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr()));
                    ruleEntity.setLastOppotunityTime(lastOppotunityTime);
                    ruleEntity.setLastSignTime(lastSignTime);
                    ruleEntity.setLastBackTime(data.getLongValue(CustomerManagementEnum.BACK_PUBLIC_DATE.getAttr()));
                    //ruleEntity.setLastDistributionTime(data.getLongValue(CustomerManagementEnum.DISTRIBUTION_DATE.getAttr()));
                    ruleEntity.setPublicGroupId(FastJsonHelper.getStringOrDefault(data, CustomerManagementEnum.PUBLIC_GROUP.getAttr(), ""));
                    ruleSeniorEntityList.add(ruleEntity);
                }
            }
        }
        return ruleSeniorEntityList;
    }

    public List<RuleSeniorEntity> transferClueRuleList(List<ClueEntityExt> customerList,String corpid,Integer businessType){
        List<RuleSeniorEntity> ruleSeniorEntityList = new ArrayList<>();
        List<PaasFormEntityExt> paasFormEntityList = paasFormModel.getEnableFormList(corpid, businessType);
        Map<Long, String> idToFormName = paasFormEntityList.stream().collect(Collectors.toMap(PaasFormEntityExt::getId, PaasFormEntityExt::getName));
        if (CollectionsUtil.isNotEmpty(customerList)){
            for (ClueEntityExt clue : customerList){
                RuleSeniorEntity ruleEntity = new RuleSeniorEntity();
                if (clue != null){
                    JSONObject data = clue.getData();
                    ruleEntity.setId(clue.getId());
                    ruleEntity.setCorpid(clue.getCorpid());
                    ruleEntity.setAppId(clue.getAppId());
                    ruleEntity.setFormId(clue.getFormId());
                    ruleEntity.setMenuId(clue.getMenuId());
                    ruleEntity.setClueStatus(data.getString(ClueEnum.CLUE_STATUS.getAttr()));
                    ruleEntity.setFormName(idToFormName.getOrDefault(clue.getFormId(),""));
                    ruleEntity.setLastNoConvertTime(clue.getAddTime());
                    ruleEntity.setName(data.getString(ClueEnum.COMPANY_NAME.getAttr()));
                    //ruleEntity.setLastDistributionTime(data.getLongValue(ClueEnum.DISTRIBUTION_DATE.getAttr()));
                    ruleEntity.setLastBackTime(data.getLongValue(ClueEnum.BACK_PUBLIC_DATE.getAttr()));
                    ruleEntity.setLastConnectTime(data.getLongValue(ClueEnum.LAST_CONNECT_TIME.getAttr()));
                    ruleEntity.setPublicGroupId(FastJsonHelper.getStringOrDefault(data, ClueEnum.PUBLIC_GROUP.getAttr(), ""));
                    ruleSeniorEntityList.add(ruleEntity);
                }
            }
        }
        return ruleSeniorEntityList;
    }

    /**
     * 去除不退回条件和退回条件的筛选条件的未启用和已删除字段,标签字段特殊处理
     * @param jsonDataArray 筛选条件
     * @param explainOpenMap 表单字段是否启用
     * @param labelIds 表单开启的标签id
     */
    public void removeNoOpenOrDelete4FilterScreen(JSONArray jsonDataArray,Map<String,Integer> explainOpenMap,List<Long> labelIds){
        Iterator<Object> iterator = jsonDataArray.iterator();
        if (explainOpenMap != null){
            while (iterator.hasNext()){
                JSONObject jsonObject = (JSONObject)iterator.next();
                Integer fieldType = jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE);
                String attr = jsonObject.getString(FieldAttrConstant.ATTR);
                //为0代表该字段 未启用或已删除
                Integer isOpen = explainOpenMap.getOrDefault(attr,0);
                //去除地址筛选条件的判断
                if(Objects.equals(isOpen,BasicConstant.ZERO) && AddressEnum.getByAlias(attr) == null){
                    iterator.remove();
                }
                //标签筛选条件处理
                if (Objects.equals(FieldTypeEnum.LABEL.getType(),fieldType) && Objects.equals(isOpen,BasicConstant.ONE)){
                    List<Long> value = jsonObject.getJSONArray("value").toJavaList(Long.class);
                    //去除已经删除的标签
                    value.retainAll(labelIds);
                    //value.removeIf(item -> !labelIds.contains(Long.parseLong(item.toString())))
                }
            }
        }
    }


    /**
     * @Description: 获取每个员工负责的客户id 和 分配时间 的映射
     * @param corpid 公司id
     * @param userId 当前用户id
     * @param customerIdList 当前负责的客户id列表
     * @return retMap
     */
    public Map<Long,Long> getCustomerUserMap(String corpid, String userId, List<Long> customerIdList) throws XbbException {
        Map<Long, Long> retMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isEmpty(customerIdList)) {
            return retMap;
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery()
                .filter(termQuery("corpid.keyword", corpid))
                .filter(termsQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.DATA_ID), customerIdList))
                .filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.USER_ID), userId))
                .filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.IS_MAIN), 1))
                .filter(termQuery("del", DelEnum.NORMAL.getDel()));
        sourceBuilder.sort(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.DISTRIBUTION_TIME), SortOrder.DESC);
        //拿固定数据
        sourceBuilder.fetchSource(new String[]{CustomerTeamEnum.getAttrConnectData(CustomerTeamEnum.DATA_ID),CustomerTeamEnum.getAttrConnectData(CustomerTeamEnum.DISTRIBUTION_TIME)},null);
        IndexTypeEnum customerTeamIndex = indexTypeModel.getTeamIndexType(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());

        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerTeamIndex.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(customerTeamIndex.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> xbbAggregatedPage = esHelper.findByPage(customerTeamIndex, boolQueryBuilder, PaasFormDataEntity.class, null, 0, 10000, null);
        if (CollectionsUtil.isNotEmpty(xbbAggregatedPage.getContent())){
            List<CustomerUserEntity> list = (List<CustomerUserEntity>) transferSubFormHelper.transferFormDataToUserTeamList(IndexTypeEnum.IDX_SAAS_CUSTOMER_TEAM, xbbAggregatedPage.getContent());
            for(CustomerUserEntity customerUser : list){
                retMap.put(customerUser.getDataId(), customerUser.getDistributionTime());
            }
        }
        return retMap;
    }




    /**
     * @Description: 获取每个员工负责的线索id 和 分配时间 的映射
     * @param corpid 公司id
     * @param userId 当前用户id
     * @param clueIdList 当前负责的线索id列表
     * @return retMap
     */
    public Map<Long,Long> getClueUserMap(String corpid, String userId, List<Long> clueIdList) throws XbbException {
        Map<Long, Long> retMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isEmpty(clueIdList)) {
            return retMap;
        }
        //排序：id asc
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery()
                .filter(termQuery("corpid.keyword", corpid))
                .filter(termsQuery(ClueTeamEnum.getEsAttr(ClueTeamEnum.DATA_ID), clueIdList))
                .filter(termQuery(ClueTeamEnum.getEsAttr(ClueTeamEnum.USER_ID), userId))
                .filter(termQuery(ClueTeamEnum.getEsAttr(ClueTeamEnum.IS_MAIN), 1))
                .filter(termQuery("del", DelEnum.NORMAL.getDel()));
        sourceBuilder.sort(ClueTeamEnum.getEsAttr(ClueTeamEnum.DISTRIBUTION_TIME), SortOrder.DESC);
        //拿固定数据
        sourceBuilder.fetchSource(new String[]{CustomerTeamEnum.getAttrConnectData(CustomerTeamEnum.DATA_ID),CustomerTeamEnum.getAttrConnectData(CustomerTeamEnum.DISTRIBUTION_TIME)},null);
        IndexTypeEnum clueTeamIndex = indexTypeModel.getTeamIndexType(corpid, XbbRefTypeEnum.CLUE.getCode());

        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, clueTeamIndex.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(clueTeamIndex.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> xbbAggregatedPage = esHelper.findByPage(clueTeamIndex, boolQueryBuilder, PaasFormDataEntity.class, null, 0, 10000, null);

        if (CollectionsUtil.isNotEmpty(xbbAggregatedPage.getContent())){
            List<ClueUserEntity> list = (List<ClueUserEntity>) transferSubFormHelper.transferFormDataToUserTeamList(IndexTypeEnum.IDX_SAAS_CLUE_TEAM, xbbAggregatedPage.getContent());
            for(ClueUserEntity clueUser : list){
                retMap.put(clueUser.getDataId(), clueUser.getDistributionTime());
            }
        }
        return retMap;
    }
}
